﻿using EHU_InterfaceProgramming;
using Microsoft.Kinect;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Windows.Threading;

namespace EHU_InterfaceProgramming
{
    public partial class MainWindow : Window
    {

        private KinectControl kinect = null;
        public SplashScreen splash;
        public outputCodeDisplay output;
        public InputCodeDisplay input;
        protected TextBlock[] InputOptions = new TextBlock[5];

        // Store the thread for the countdown
        private System.Windows.Threading.DispatcherTimer dt = null;

        public MainWindow()
        {
            
            InitializeComponent();


            // Initialise the Code output class which handles the displaying
            // of the current code and also allows it to be printed to a file
            output = new outputCodeDisplay(this.txtCodeOutput, this);

            output.printCode("program1");
            output.openingBrace();
          
            output.addComment("This is a comment for the code!");
            output.ifStatement();
            output.printCode("(someValue == 1)");
            output.openingBrace();
            output.printCode("    exit();");
            output.closingBrace();
            output.closingBrace();
            string[] inputoptions = new string[5] {"Class","Method","If","For","save"};
            
            input = new InputCodeDisplay(this.txtSuggestedAction1, this.txtSuggestedAction2, this.txtSuggestedAction3, this.txtSuggestedAction4, this.txtSuggestedAction5);

            if (input != null)
            {
                input.setOptions(inputoptions);
            }


            Logger.LogAdded += new EventHandler(MyLogger_LogAdded);

            Logger.Log("showing splash screen");
            // Once the main window is loaded, initialise the splash screen
            // which should then await the initialisation of the Kinect
            splash = new SplashScreen(this);
            splash.show();
            Logger.Log("splash screen should be showing");

            EnableKinect();
            splash.updateKinectStatusImage();
        }

        void MyLogger_LogAdded(object sender, EventArgs e)
        {
            //txtLog.Text = txtLog.Text + Environment.NewLine + Logger.GetLastLog();
            string log = Logger.GetLastLog();
            //if a $ preceeds the log entry, it is not for output, and is processed here.
            if (log.Contains("$") == true)
            {
                if (log == "$circle")
                {
                    for (int i = 0; i <= 4; i++)
                    {
                        if (InputOptions[i].Text == "For")
                        {
                            optionSelected(i);
                        }
                        else
                        {
                            Logger.Log("For loop not available at the moment, check to make sure you can put an if statment here.");
                        }

                    }
                }
                else if (log == "$Push Up")
                {
                    for (int i = 0; i <= 4; i++)
                    {
                        if (InputOptions[i].Text == "If")
                        {
                            optionSelected(i);
                        }
                        else
                        {
                            Logger.Log("If statment not available at the moment, check to make sure you can put an if statment here.");
                        }

                    }
                }
            }
            else
            {
                log = DateTime.Now + ": " + log + "\n";

                // Append the log to the log window
                txtLogArea.AppendText(log);
                txtLogArea.ScrollToEnd();

                // Write it to the console
                Console.Write(log);
            }
        }

        /// <summary>
        /// This method shows the action text in the main window which displays in a fading affect
        /// </summary>
        /// <param name="text"></param>
        public void showActionText(String text)
        {
            actionText.Text = text;
            actionText.Opacity = 1;

            /**
            * Start a thread for theanimation effect*/
            if (dt != null)
            {
                dt.Stop();
            }

            dt = new System.Windows.Threading.DispatcherTimer();
            dt.Interval = new TimeSpan(0, 0, 0, 0, 100); // 10th of a second
            dt.Tick += new EventHandler(dt_Tick);
            dt.Start();

        }
        /**
         * Process the thread for showing the animation effect
         * */
        void dt_Tick(object sender, EventArgs e)
        {
            // Repaint the text with the updated opacity
            actionText.Opacity = actionText.Opacity - 0.05;

            if (actionText.Opacity == 0)
            {
                actionText.Visibility = Visibility.Hidden;
                dt.Stop();
                dt = null;
            }
        }

        /**
         * Initialise the kinect here
         **/
        public void EnableKinect()
        {
            Console.WriteLine("loading form..");
            kinect = new KinectControl(this);

            // if the Kinect has not initialised we need to update this 
            // object reference and set it to null.

            // Set the slider to a position based on the position of the Kinect
            // elevation 
            if (kinect.sensor != null && kinect.sensor != null)
            {
                sldrSensorPosition.Value = kinect.sensor.ElevationAngle;
            }
        }

        /**
         * Called when the Kinect has finished initilaising
         * Hide the splash screen and show the main window
         * */
        public void onKinectInitialise()
        {
            splash.hide();
            mainWindowInterface.Visibility = Visibility.Visible;
        }


        /**
         * Deactive the kinect here
         **/
        private void frmKinectInterface_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (kinect.sensor != null) {
                kinect.disable_kinect();
            }
            System.Environment.Exit(0);
        }

        /**
        * This is basically a mirror of the method within the KinectControl
        * class. Return true if the Kinect sensor is found otherwise 0.
        **/
        public Boolean isKinectConnected()
        {
            if (kinect == null || kinect.sensor == null)
            {
                return false;
            }
            return kinect.isKinectConnected();
        }


        private void chkNearMode_Checked(object sender, RoutedEventArgs e)
        {
                //  Enable near mode
                kinect.sensor.DepthStream.Range = DepthRange.Near;
                kinect.sensor.SkeletonStream.EnableTrackingInNearRange = true;
                kinect.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;
                Logger.Log("Near mode enabled");
                showActionText("Near mode enabled");
        }

        private void chkNearMode_Unchecked(object sender, RoutedEventArgs e)
        {
            // Disable near mode
            kinect.sensor.DepthStream.Range = DepthRange.Default;
            kinect.sensor.SkeletonStream.EnableTrackingInNearRange = false;
            kinect.sensor.SkeletonStream.TrackingMode = SkeletonTrackingMode.Default;
            Logger.Log("Near mode disabled");
            showActionText("Near mode disabled");
        }

        private void btnSensorAdjust_Click(object sender, RoutedEventArgs e)
        {
            int angle = (int)sldrSensorPosition.Value;
            kinect.sensor.ElevationAngle = angle;
            Logger.Log("Changing Sensor angle to: " + angle + " degrees.");
            showActionText("Sensor angle adjusted.");
        }
//========Region Input Processing===========================
          /// <summary>
        /// Initialises the 5 Options on the GUI to ensure that they are blank, 
        /// also registers the textbox objects from the GUI to ensure that they can be tracked from here. 
        /// </summary>
        /// <param name="txtA">TextBlock Object A </param>
        /// <param name="txtB">TextBlock Object B </param>
        /// <param name="txtC">TextBlock Object C </param>
        /// <param name="txtD">TextBlock Object D </param>
        /// <param name="txtE">TextBlock Object E </param>
        public void InputCodeDisplay(TextBlock txtA, TextBlock txtB, TextBlock txtC,TextBlock txtD,TextBlock txtE)
        {
            InputOptions[0] = txtA;
            InputOptions[1] = txtB;
            InputOptions[2] = txtC;
            InputOptions[3] = txtD;
            InputOptions[4] = txtE;

            for (int i = 0; i <= 4; i++)
            {
                InputOptions[i].Text = "";
            }
            
        }

       
        /// <summary>
        /// Set the 5 options on the GUI. 
        /// If an option is left blank, its corrisponding control will be disabled on the GUI
        /// </summary>
        /// <param name="Options"> A five element string array containing the options to be set.
        /// Option A is set from element 0 through to E in element 4.</param>
        public void setOptions(string[] Options)
        {
            for (int i = 0; i <= 4; i++)
            {
                InputOptions[i].Text = Options[i];
                if (Options[i] == "")
                {
                    InputOptions[i].Visibility = System.Windows.Visibility.Hidden;
                }
                else if (Options[i] != "" && InputOptions[i].Visibility == System.Windows.Visibility.Hidden)
                {
                    InputOptions[i].Visibility = System.Windows.Visibility.Visible;
                }

            }
        }
        /// <summary>
        /// Takes the option selected by the user from the suggested code options, and calles the 
        /// relevant outputCodeDisplayMethods to add the code to the output window.
        /// </summary>
        /// <param name="selected">The option selected by the user.</param>
        public void optionSelected(int selected)
        {
            string optionChosen = InputOptions[selected].Text;
            switch (optionChosen)
            { 
                   
                case "Class":
                    output.ClassStatement("Public",true);
                    return;

                case "Method":
                   
                    return;

                case "If":
                    output.ifStatement();
                    output.print("(");
                    string[] options = new string[5] {"Greater Than","Less Than","Equal to","Not EqualTo","",};
                    setOptions(options);
                    return;

                case "For":
                    return;
            }

        }
     
    }
}
